﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sample.Run.SystemFile;
using Kocic.RepositoryManagement.SystemFile;
using System.IO;

namespace Sample.Run
{
    public static class SystemFileSamples
    {
        #region File Path Declarations

        private static readonly String BASIC_ORIGINAL_FILE_PATH = @"C:\Source\Repository Management Framework\Sample.Run\Samples\System File\Files\BasicFile.txt";
        private static readonly String BASIC_OUTPUT_FILE_PATH = @"C:\Source\Repository Management Framework\Sample.Run\Samples\System File\Files\BasicFileOutput.txt";
        private static readonly String DELIMITED_ORIGINAL_FILE_PATH = @"C:\Source\Repository Management Framework\Sample.Run\Samples\System File\Files\DelimitedFile.txt";
        private static readonly String DELIMITED_OUTPUT_FILE_PATH = @"C:\Source\Repository Management Framework\Sample.Run\Samples\System File\Files\DelimitedFileOutput.txt";


        #endregion

        public static void Run()
        {
            #region Example #1 : Basic File Read, Write Operations

            Console.WriteLine("System File Samples ---------------------------\n");
            Console.WriteLine("Example: #1 ------------------------------------------");

            SystemFileSamples.CleanUp();

            //Create context instance
            using (new SystemFileExecutionContext<FileContext>(SystemFileSamples.BASIC_OUTPUT_FILE_PATH))
            {
                using (BasicFileRepositoryManager manager = new BasicFileRepositoryManager())
                {
                    manager.Updated += (s, e) =>
                    {
                        Console.WriteLine("Line: " + e.DataObject.Contents + " updated.");
                    };

                    manager.Created += (s, e) =>
                    {
                        Console.WriteLine("Line: " + e.DataObject.Contents + " created.");
                    };

                    manager.Deleted += (s, e) =>
                    {
                        Console.WriteLine("Line: " + e.DataObject.Contents + " deleted.");
                    };

                    //Fetch line #1
                    LineObject firstLine = manager.RetrieveSingle(1);
                    Console.WriteLine("Contents of retrieved line: " + firstLine.Contents);

                    //Insert new line
                    LineObject newLine = new LineObject();
                    newLine.Contents = "This is a new line. Example 1";
                    manager.Save(newLine);

                    LineObject newLine2 = new LineObject();
                    newLine2.Contents = "This is also a new line. Example 1";
                    manager.Save(newLine2);

                    //Update first line
                    firstLine.Contents = "First line contents have been changed. Example 1";
                    manager.Save(firstLine);

                    //Delete line
                    manager.Delete(newLine2);
                }
            }

            #endregion

            #region Example #2 : Deferring Operations

            Console.WriteLine("\n\nExample: #2 ------------------------------------------");

            SystemFileSamples.CleanUp();

            //Create context instance
            using (new SystemFileExecutionContext<FileContext>(SystemFileSamples.BASIC_OUTPUT_FILE_PATH))
            {
                //Create deferrer instance
                using (new SystemFileContextDeferrer<FileContext>())
                {
                    using (BasicFileRepositoryManager manager = new BasicFileRepositoryManager())
                    {
                        //Subscribe to these events because of deferral. These events occur before the actual commit operation takes place
                        manager.Updating += (s, e) =>
                        {
                            Console.WriteLine("Line: " + e.DataObject.Contents + " updating.");
                        };

                        manager.Creating += (s, e) =>
                        {
                            Console.WriteLine("Line: " + e.DataObject.Contents + " creating.");
                        };

                        manager.Deleting += (s, e) =>
                        {
                            Console.WriteLine("Line: " + e.DataObject.Contents + " deleting.");
                        };

                        //Fetch line #1
                        LineObject firstLine = manager.RetrieveSingle(1);
                        Console.WriteLine("Contents of retrieved line: " + firstLine.Contents);

                        //Insert new line
                        LineObject newLine = new LineObject();
                        newLine.Contents = "This is a new line. Example 2.";
                        manager.Save(newLine);

                        LineObject newLine2 = new LineObject();
                        newLine2.Contents = "This is also a new line. Example 2";
                        manager.Save(newLine2);

                        //Update first line
                        firstLine.Contents = "First line contents have been changed. Example 2";
                        manager.Save(firstLine);

                        //Delete line
                        manager.Delete(newLine2);
                    }
                }
            }
            #endregion

            #region Example #3 : Static Operations

            Console.WriteLine("\n\nExample: #3 ------------------------------------------");

            SystemFileSamples.CleanUp();

            //Create context instance
            using (new SystemFileExecutionContext<FileContext>(SystemFileSamples.BASIC_OUTPUT_FILE_PATH))
            {
                //Fetch line #1
                LineObject firstLine = SystemFileRepositoryManager<LineObject, FileContext>.Retrieve(l => l.LineNumber == 1).SingleOrDefault();
                Console.WriteLine("Contents of retrieved line: " + firstLine.Contents);

                //Insert new line
                LineObject newLine = new LineObject();
                newLine.Contents = "This is a new line. Example 3.";
                SystemFileRepositoryManager<LineObject, FileContext>.SaveLineObject(newLine);

                Console.WriteLine("Line: " + newLine.Contents.ToString() + " created.");

                //Insert new line
                LineObject newLine2 = new LineObject();
                newLine2.Contents = "This is also a new line. Example 3";
                SystemFileRepositoryManager<LineObject, FileContext>.SaveLineObject(newLine2);

                Console.WriteLine("Line: " + newLine2.Contents.ToString() + " created.");

                //Update first line
                firstLine.Contents = "First line contents have been changed. Example 3 previously being: " + firstLine.Contents;
                SystemFileRepositoryManager<LineObject, FileContext>.SaveLineObject(firstLine);

                Console.WriteLine("Line: " + firstLine.Contents.ToString() + " updated.");

                //Insert line at specific line number
                LineObject insertAt = new LineObject() { Contents = "Bam!!" };
                SystemFileRepositoryManager<LineObject, FileContext>.SaveLineObject(insertAt, 1);

                Console.WriteLine("Line: " + insertAt.Contents.ToString() + " inserted at line number 1.");

                //Delete line
                SystemFileRepositoryManager<LineObject, FileContext>.DeleteLineObject(newLine2);

                Console.WriteLine("Lin: " + newLine2.Contents.ToString() + " deleted.");

                //Update line at specific line number
                LineObject updateAt = SystemFileRepositoryManager<LineObject, FileContext>.Retrieve(l => l.LineNumber == 2).SingleOrDefault();
                updateAt.Contents = "This line was updated from previous value of: " + updateAt.Contents + " formerly at line number " + updateAt.LineNumber.ToString();
                SystemFileRepositoryManager<LineObject, FileContext>.SaveLineObject(updateAt, 3);

                Console.WriteLine("Line " + updateAt.Contents.ToString() + " updated at line number 3.");
            }
            #endregion

            #region Example #4 : Delimited File and Combination Repository Managers

            Console.WriteLine("\n\nExample: #4 ------------------------------------------");

            SystemFileSamples.CleanUp();

            //Create context instance
            using (new SystemFileExecutionContext<FileContext>(SystemFileSamples.DELIMITED_OUTPUT_FILE_PATH))
            {
                using (new SystemFileContextDeferrer<FileContext>())
                {
                    //Fetch first line as a PersonLineObject
                    var firstLine = SystemFileRepositoryManager<PersonLineObject, FileContext>.Retrieve(l => l.LineNumber == 1).Select(l => new PersonLineObject() { Contents = l.Contents }).SingleOrDefault();

                    Console.WriteLine("Contents of retrieved line: " + firstLine.Contents);

                    //Save new person to 1st line with setting properties directly in constructor
                    var newLine = new PersonLineObject("John", "Smith", "21");
                    SystemFileRepositoryManager<PersonLineObject, FileContext>.SaveLineObject(newLine, 1);

                    Console.WriteLine("Line: " + newLine.Contents + " created.");

                    //Save new person to 1st line with setting contents directly
                    var newLine2 = new PersonLineObject() {Contents = "Leo,Smith,25" };
                    SystemFileRepositoryManager<PersonLineObject, FileContext>.SaveLineObject(newLine2, 1);

                    Console.WriteLine("Line: " + newLine2.Contents.ToString() + " created.");

                    //Use another manager to delete the line
                    using (BasicFileRepositoryManager manager = new BasicFileRepositoryManager())
                    {
                        manager.Deleting += (s, e) =>
                        {
                            Console.WriteLine("Line: " + e.DataObject.Contents + " deleting.");
                        };

                        manager.Delete(newLine2);
                    }
                }
            }

            #endregion          
        }

        #region Helpers
        private static void CleanUp()
        {
            Console.WriteLine("\nCleanup...\n");
            if (File.Exists(SystemFileSamples.BASIC_OUTPUT_FILE_PATH))
            {
                File.Delete(SystemFileSamples.BASIC_OUTPUT_FILE_PATH);
            }

            if (File.Exists(SystemFileSamples.DELIMITED_ORIGINAL_FILE_PATH))
            {
                File.Delete(SystemFileSamples.DELIMITED_OUTPUT_FILE_PATH);
            }

            File.Copy(SystemFileSamples.BASIC_ORIGINAL_FILE_PATH, SystemFileSamples.BASIC_OUTPUT_FILE_PATH);
            File.Copy(SystemFileSamples.DELIMITED_ORIGINAL_FILE_PATH, SystemFileSamples.DELIMITED_OUTPUT_FILE_PATH);
        }
        #endregion
    }
}